package com.zxb.base.system;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zxb.base.system.vo.DictConfigVo;
import com.zxb.core.common.A;
import com.zxb.core.common.C;
import com.zxb.core.common.R;
import com.zxb.core.dao.system.SysDict;
import com.zxb.core.dao.system.SysDictDao;
import com.zxb.base.system.vo.DictExportVo;
import com.zxb.core.common.service.MinioService;
import com.zxb.core.util.excel.ExcelImportUtil;
import com.zxb.core.util.excel.IExcel;
import com.zxb.base.system.vo.DictBatchVo;
import lombok.RequiredArgsConstructor;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author Zxb
 */
@RestController
@RequiredArgsConstructor
public class DictController {
    private final SysDictDao dictDao;
    private final MinioService minioService;

    @PostMapping("/dict/add")
    public R add(@RequestBody @Valid SysDict obj) {
        if (dictDao.exists(
                new QueryWrapper<SysDict>()
                        .lambda()
                        .eq(SysDict::getName, obj.getName())
                        .isNull(SysDict::getPid)
        )) {
            return R.error("字典名称已经存在");
        }
        if (dictDao.exists(
                new QueryWrapper<SysDict>()
                        .lambda()
                        .eq(SysDict::getCode, obj.getCode())
                        .isNull(SysDict::getPid)
        )) {
            return R.error("字典编码已经存在");
        }
        obj.setLayer(1);
        obj.setSort(0);
        dictDao.save(obj);
        return R.success();
    }

    @GetMapping("/dict/info")
    public R info(String parentCode, String code) {
        String nullVal = "-";
        SysDict parent = dictDao.getOne(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getCode, parentCode)
        );
        if (parent == null) {
            return R.success(nullVal);
        }
        SysDict obj = dictDao.getOne(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getPid, parent.getId())
                        .eq(SysDict::getCode, code)
        );
        if (obj == null) {
            return R.success(nullVal);
        }
        return R.success(obj.getName());
    }

    @PostMapping("/dict/update")
    public R update(@RequestBody @Valid SysDict obj) {
        SysDict old = dictDao.getById(obj.getId());
        A.isInDatabase(old, "字典");
        if (dictDao.exists(
                new QueryWrapper<SysDict>()
                        .lambda()
                        .eq(SysDict::getName, obj.getName())
                        .ne(SysDict::getId, obj.getId())
        )) {
            return R.error("字典名称已经存在");
        }
        if (dictDao.exists(
                new QueryWrapper<SysDict>()
                        .lambda()
                        .eq(SysDict::getCode, obj.getCode())
                        .ne(SysDict::getId, obj.getId())
        )) {
            return R.error("字典编码已经存在");
        }
        BeanUtil.copyProperties(obj, old, C.IGNORED_PROPERTIES);
        dictDao.updateById(old);
        return R.success();
    }

    @PostMapping("/dict/batch")
    public R batch(@RequestBody DictBatchVo param) {
        List<Long> idList = param.getIds();
        for (Long id : idList) {
            SysDict old = dictDao.getById(id);
            if (old != null) {
                if (param.getIsUseCk()) {
                    old.setIsUse(param.getIsUse());
                }
                dictDao.updateById(old);
            }
        }
        return R.success();
    }

    @PostMapping("/dict/del")
    public R del(@RequestBody List<Long> ids) {
        dictDao.removeBatchByIds(ids);
        return R.success();
    }

    @GetMapping("/dict/list")
    public R findByCode(String code) {
        SysDict obj = dictDao.getOne(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getCode, code)
                        .isNull(SysDict::getPid));
        if (obj == null) {
            return R.success(Arrays.asList());
        }
        List<SysDict> list = dictDao.list(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getPid, obj.getId())
                        .orderByAsc(SysDict::getSort)
        );
        return R.success(list);
    }

    @GetMapping("/dict/page")
    public R page(String searchStr, Integer page, Integer pageSize) {
        IPage<SysDict> pageParam = new Page<>(page, pageSize);
        LambdaQueryWrapper<SysDict> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(SysDict::getPid);
        if (StrUtil.isNotBlank(searchStr)) {
            queryWrapper.like(SysDict::getName, "%" + searchStr + "%");
        }
        IPage<SysDict> result = dictDao.page(pageParam, queryWrapper);
        return R.success(result);
    }

    @PostMapping("/dict/config")
    @Transactional(rollbackFor = Exception.class)
    public R config(@RequestBody @Valid DictConfigVo dictConfigVo) {
        String code = dictConfigVo.getCode();
        SysDict obj = dictDao.getOne(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getCode, code)
                        .isNull(SysDict::getPid));
        if (obj == null) {
            return R.error("未查询到字典");
        }
        List<SysDict> dictList = dictConfigVo.getList();
        dictList.forEach(t -> {
            t.setPid(obj.getId());
            t.setLayer(2);
        });
        dictDao.remove(
                new LambdaQueryWrapper<SysDict>()
                        .eq(SysDict::getPid, obj.getId())
        );
        dictDao.saveBatch(dictList);
        return R.success();
    }

    @PostMapping("/dict/export")
    public void export(HttpServletResponse response) throws IOException {
        List<SysDict> list = dictDao.list();
        List<DictExportVo> dataList = list.stream().map(t -> DictExportVo.builder()
                .name(t.getName())
                .code(t.getCode())
                .parentName("")
                .parentCode("")
                .build()).collect(Collectors.toList());
        String fileName = UUID.randomUUID().toString();
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), DictExportVo.class)
                .sheet(fileName).doWrite(dataList);
    }

    @PostMapping("/dict/import")
    public R<?> add(@RequestParam("file") MultipartFile file) throws IOException {
        String path = minioService.upload(file);
        InputStream is = minioService.getObject(path);
        List<SysDict> addList = new ArrayList<>();
        List<SysDict> updateList = new ArrayList<>();
        List<String> resultList = ExcelImportUtil.importDataByExcel(is, new IExcel() {

            @Override
            public boolean isRowHasData(XSSFRow row) {
                String name = ExcelImportUtil.getCellVal(row, 0);
                return StrUtil.isNotBlank(name);
            }

            @Override
            public String importRow(XSSFRow row) {
                String name = ExcelImportUtil.getCellVal(row, 0);
                try {
                    Thread.sleep(1000);
                    return "name:" + name;
                } catch (InterruptedException e) {
                    return "第" + row.getRowNum() + "行发生异常";
                }
            }

        });
        return R.success(resultList);
    }
}
